Segments split the ELF binary into parts which are then loaded into memory by the OS programme loader. They can be thought of as grouping sections by their attributes and only selecting those which will be loaded into memory. In essence, segments contain information needed at runtime, while sections contain information needed at link-time.
Segments are described by programme headers which are stored in the Programme Header Table (PHT). These structs are again defined in <elf.h>
:
typedef struct
{
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
} Elf32_Phdr;
typedef struct
{
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
} Elf64_Phdr;
p_type
- describes the type of the segment.p_offset
- the offset from the beginning of the file where the segment resides.p_vaddr
- the virtual address at which the segment resides in memory.p_paddr
- the segment's physical address, which is relevant only for systems with physical addressing. This member holds unspecified contents for executables and shared objectsp_filesz
- the number of bytes the segment occupies in the file image. It may be 0.p_memsz
- the number of bytes the segment occupies in the memory image. It may be 0.p_align
- the value to which the segments are aligned in the file and in memory. If this holds 0 or 1, then no alignment is required. Otherwise, p_align
should be a positive integer power of 2 and p_vaddr
should be equal to p_offset % p_align
.The PHT can be viewed by specifying the -l
argument to readelf
:
Name | Value |
---|---|
PT_NULL |
0 |
PT_LOAD |
1 |
PT_DYNAMIC |
2 |
PT_INTERP |
3 |
PT_NOTE |
4 |
PT_SHLIB |
5 |
PT_PHDR |
6 |
PT_TLS |
7 |
PT_LOOS |
0x60000000 |
PT_HIOS |
0x6fffffff |
PT_LOPROC |
0x70000000 |
PT_HIPROC |
0x7fffffff |
PT_LOAD
This specifies a loadable segment described by p_filesz
and p_memsz
which means the segment is going to be mapped into memory. Bytes from the file are mapped to the beginning of the memory segment. Should the memory size be larger than the file size, the extra bytes are filled with 0s and are placed after the segment's data. Note that the file size cannot be larger than the memory size.
Entries of this type are sorted in an ascending order in the PHT according to their p_vaddr
field.
All executable files must contain at least one PT_LOAD
segment.
PT_DYNAMIC
The dynamic segment is pertinent to executables which avail themselves of dynamic linking and contains information for the dynamic linker. It typically points to the .dynamic
section and comprises a series of structures which hold the relevant information.
typedef struct
{
Elf32_Sword d_tag; /* Dynamic entry type */
union
{
Elf32_Word d_val; /* Integer value */
Elf32_Addr d_ptr; /* Address value */
} d_un;
} Elf32_Dyn;
typedef struct
{
Elf64_Sxword d_tag; /* Dynamic entry type */
union
{
Elf64_Xword d_val; /* Integer value */
Elf64_Addr d_ptr; /* Address value */
} d_un;
} Elf64_Dyn;
In essence, the d_tag
field determines whether the d_un
field is treated as a value or an address.
PT_NOTE
This segment is completely optional and may contain information that is pertinent to a specific system. It can hold a variable number of entries of size 4 or 8 bytes on 32-bit and 64-bit platforms, respectively.
PT_INTERP
Here are specified the location and size of a null terminated string which describes the programme interpreter. Only one such segment is allowed per file and it must also precede any PT_LOAD
segments.
PT_PHDR
This segment contains the location and size of the Programme Header Table itself, both in the file and in memory. Similarly to PT_INTERP
, only one such segment is allowed per file and it must also precede any PT_LOAD
segments.
PT_TLS
This segment specifies the Thread-Local Storage template. The latter is an amalgamation of all sections of type SHF_TLS
. TLS sections are used to specify the size and initial contents of data whose copies are to be associated with different threads of execution. The part of the TLS which holds this initialised data is referred to as the TLS initialisation image, while the rest of the template is comprised of one or more sections of type SHF_NOBITS
.
Member | Value |
---|---|
p_offset |
File offset of the TLS initialization image |
p_vaddr |
Virtual memory address of the TLS initialization image |
p_paddr |
reserved |
p_filesz |
Size of the TLS initialization image |
p_memsz |
Total size of the TLS template |
p_flags |
PF_R |
p_align |
Alignment of the TLS template |
PT_SHLIB
is reserved but is unspecified, while values from PT_LOOS
to PT_HIOS
and from PT_LOPROC
through PT_HIPROC
are reserved for OS- and processor-specific semantics, respectively.
The p_flags
field describes the permissions the segment is equipped with. It is important to note that the system may actually give more access than requested with the exception that a segment will never be assigned write permissions, unless explicitly requested:
Flags | Value | Exact | Allowable |
---|---|---|---|
none | 0 | All access denied | All access denied |
PF_X |
1 | Execute only | Read, execute |
PF_W |
2 | Write only | Read, write, execute |
PF_W+PF_X |
3 | Write, execute | Read, write, execute |
PF_R |
4 | Read only | Read, execute |
PF_R+PF_X |
5 | Read, execute | Read, execute |
PF_R+PF_W |
6 | Read, write | Read, write, execute |
PF_R+PF_W+PF_X |
7 | Read, write, execute | Read, write, execute |